package com.winner.data.util;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.winner.data.entity.Menu;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;

/**
 * 使用Hutool工具类快速生成树形结构, 在做业务时,灵活选用树形结构 或 列表结构
 *
 * https://blog.csdn.net/chengmeng_123/article/details/74984116  mysql全国省市区县表（带经纬度）
 *
 * @author wangxinle5
 * @since 2023-07-04
 */
public class TreeUtils {

    public static void main(String[] args) {
        // 模拟数据库查询出来的全量菜单数据 id parentId 字段都是String类型, 最顶层一般设为0 或 null
        // 注意如果查询的list的id重复,那么构造的树就会丢数据, 所以必须保证id唯一
        ArrayList<Menu> menuList = new ArrayList<>();
        menuList.add(new Menu("1", "0", "系统管理"));
        menuList.add(new Menu("11", "1", "用户管理"));
        menuList.add(new Menu("111", "11", "用户添加"));
        menuList.add(new Menu("2", "0", "店铺管理"));
        menuList.add(new Menu("21", "2", "商品管理"));
        menuList.add(new Menu("221", "2", "商品管理2"));
//         List<TreeNode<String>> menuList = Arrays.asList(objecztTreeNode); 就可以不用新建Menu对象了
        List<Tree<String>> trees = getTrees(menuList);
        System.out.println("全量的树形结构是: " + JSON.toJSONString(trees));

        // 递归查找顶部菜单是id=1下所有的子菜单的id
        String parentId = "1";
        List<String> result = findIdsByParentId(trees, parentId);

        // 打印结果
        for (String id : result) {
            System.out.println(id);
        }
    }

    /**
     * 数据库实体类, id parentId 字段都是String类型, hutool工具类生成树结构
     *
     * @param menuList
     * @return 树结构
     */
    private static List<Tree<String>> getTrees(ArrayList<Menu> menuList) {
        // 配置类
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        // 自定义属性名 (若不指定名称, 则就使用默认的名称, 默认名称就是  id  parentId  name)
        treeNodeConfig.setIdKey("id");
        treeNodeConfig.setParentIdKey("parentId");
        treeNodeConfig.setNameKey("name");
        // treeNodeConfig.setDeep(20); 递归深度,默认无限制
        // 构建树形 "0"表示最顶层的parentId是"0"   一般不定义递归深度 和 属性名称, treeNodeConfig参数可以不要
        return TreeUtil.build(menuList, StringPool.ZERO, treeNodeConfig, ((object, treeNode) -> {
            treeNode.setId(object.getId());
            treeNode.setParentId(object.getParentId());
            treeNode.setName(object.getName());
            treeNode.putExtra("key", "Menu类的另一个成员变量"); // 扩展字段
        }));
    }

    public static List<String> findIdsByParentId(List<Tree<String>> treeList, String parentId) {
        List<String> idList = new ArrayList<>();
        if (CollUtil.isNotEmpty(treeList)) {
            for (Tree node : treeList) {
                Tree childNode = TreeUtil.getNode(node, parentId);
                if (Objects.nonNull(childNode)) {
                    getChildIdList(idList, childNode);
                    break;
                }
            }
        }
        return idList;
    }

    /**
     * 递归查询出组织树子节点Id列表
     *
     * @param idList 子节点Id列表
     * @param parentNode 父节点
     */
    private static void getChildIdList(List<String> idList, Tree<String> parentNode) {
        idList.add(parentNode.getId()); // 获取扩展字段加入idList用 idList.add(parentNode.get("key").toString())
        if (!parentNode.hasChild()) {
            return;
        }
        List<Tree<String>> childrenList = parentNode.getChildren();
        for (Tree node : childrenList) {
            getChildIdList(idList, node);
        }
    }

}
